﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JXT.PrimaryKey.Batman.Extensions;
using JXT.PrimaryKey.Batman.Validation;
using JXT.PrimaryKey.Batman.Collections;
using JXT.PrimaryKey.Batman.Domain.Models;
using JXT.PrimaryKey.Batman.Domain.Services;
using JXT.PrimaryKey.Batman.Domain.Repositories;
using JXT.PrimaryKey.Batman.Domain.Specifications;
using JXT.PrimaryKey.Batman.Domain.UserSystem.Models;
using JXT.PrimaryKey.Batman.Domain.UserSystem.Repositories;

namespace JXT.PrimaryKey.Batman.Domain.UserSystem.Services.Default
{
    public class SystemUserService : CachedServiceBase<SystemUser>, ISystemUserService
    {
        public SystemUser Add(SystemUser entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            var result = Validator.Validate(entity);
            if (!result.IsValid)
                throw new ValidationException("entity validate error!", result.Errors);
            entity.LastLoginTime = DateTime.Now;
            entity.RegisterTime = DateTime.Now;
            entity.SysId = Guid.NewGuid().ToGuidString();
            entity.SysKey = Guid.NewGuid().ToGuidString();
            LoadRepository<ISystemUserRepository>().Add(entity);
            ClearCache();
            return entity;
        }

        public SystemUser UpdateKey(SystemUser entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            entity.SysKey = Guid.NewGuid().ToGuidString();
            LoadRepository<ISystemUserRepository>().Update(entity);
            ClearCache();
            return entity;
        }

        public void Delete(SystemUser entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            RepositoryContext.BeginTransaction();
            try
            {
                LoadRepository<ISystemUserRepository>().DeleteStatus(entity.SysId);
                LoadRepository<ISystemUserRepository>().Delete(entity.Id);
                RepositoryContext.CommitTransaction();
            }
            catch
            {
                RepositoryContext.RollbackTransaction();
                throw;
            }
            finally
            {
                RepositoryContext.DisposeTransaction();
            }
        }

        public IPagedCollection<SystemUser> GetList(IPagedSpecification<SystemUser> specification)
        {
            var list = LoadRepository<ISystemUserRepository>().GetList(specification);
            return list;
        }

        public SystemStatus GetStatus(SystemUser user)
        {
            if (user == null)
                throw new ArgumentNullException("user");
            var result = LoadRepository<ISystemUserRepository>().GetStatus(user.SysId);
            return result;
        }

        public void AddStatus(SystemUser user, SystemStatus status)
        {
            if (user == null)
                throw new ArgumentNullException("entity");
            if (status == null)
                throw new ArgumentNullException("status");
            RepositoryContext.BeginTransaction();
            try
            {
                LoadRepository<ISystemUserRepository>().DeleteStatus(user.SysId);
                status.SysId = user.SysId;
                LoadRepository<ISystemUserRepository>().AddStatus(status);
                RepositoryContext.CommitTransaction();
            }
            catch
            {
                RepositoryContext.RollbackTransaction();
                throw;
            }
            finally
            {
                RepositoryContext.DisposeTransaction();
            }
        }

        public void DeleteStatus(SystemUser user)
        {
            if (user == null)
                throw new ArgumentNullException("user");
            LoadRepository<ISystemUserRepository>().DeleteStatus(user.SysId);
        }

        public SystemStatus Login(string id, string key, string ip)
        {
            if (String.IsNullOrEmpty(id))
                throw new ArgumentException("id can not be null or empty.");
            if (String.IsNullOrEmpty(key))
                throw new ArgumentException("key can not be null or empty.");
            if (String.IsNullOrEmpty(ip))
                throw new ArgumentException("ip can not be null or empty.");
            var specification = SpecificationFactory.CreateSpecification<SystemUser>();
            specification.And(e => e.SysId == id);
            specification.And(e => e.SysKey == key);
            var find = LoadRepository<ISystemUserRepository>().GetSingle(specification);
            if (find == null)
                return null;
            find.LastLoginIp = ip;
            find.LastLoginTime = DateTime.Now;
            SystemStatus status = new SystemStatus()
            {
                ClientIp = ip,
                CreateTime = DateTime.Now,
                LastActiveTime = DateTime.Now,
                SysId = find.SysId,
                DynamicKey = Guid.NewGuid().ToGuidString()
            };

            RepositoryContext.BeginTransaction();
            try
            {
                LoadRepository<ISystemUserRepository>().Update(find);
                LoadRepository<ISystemUserRepository>().DeleteStatus(find.SysId);
                LoadRepository<ISystemUserRepository>().AddStatus(status);
                RepositoryContext.CommitTransaction();
                return status;
            }
            catch
            {
                RepositoryContext.RollbackTransaction();
                throw;
            }
            finally
            {
                RepositoryContext.DisposeTransaction();
            }
        }

        public void Logout(string id, string dynamicKey, string ip)
        {
            if (String.IsNullOrEmpty(id))
                throw new ArgumentException("id can not be null or empty.");
            if (String.IsNullOrEmpty(dynamicKey))
                throw new ArgumentException("dynamickey can not be null or empty.");
            var specification = SpecificationFactory.CreateSpecification<SystemUser>();
            specification.And(e => e.SysId == id);
            var find = LoadRepository<ISystemUserRepository>().GetSingle(specification);
            if (find == null)
            {
                return;
                //throw new InvalidOperationException("can not find this login status.");
            }
            var status = LoadRepository<ISystemUserRepository>().GetStatus(find.SysId);
            if (status != null && status.DynamicKey == dynamicKey && status.ClientIp == ip)
            {
                LoadRepository<ISystemUserRepository>().DeleteStatus(status.SysId);
            }
        }

        public bool CheckStatus(string id, string dynamicKey, string ip)
        {
            if (String.IsNullOrEmpty(id))
                throw new ArgumentException("id can not be null or empty.");
            if (String.IsNullOrEmpty(dynamicKey))
                throw new ArgumentException("dynamickey can not be null or empty.");
            if (String.IsNullOrEmpty(ip))
                throw new ArgumentException("ip can not be null or empty.");
            var status = LoadRepository<ISystemUserRepository>().GetStatus(id);
            if (status == null || status.DynamicKey != dynamicKey)
                throw new InvalidOperationException("status authentication failed!");
            if (status.ClientIp != ip)
                throw new InvalidOperationException("ip authentication failed!");
            status.LastActiveTime = DateTime.Now;
            LoadRepository<ISystemUserRepository>().UpdateStatus(status);
            return true;
        }

        public override RepositoryContext RepositoryContext
        {
            get
            {
                return LoadRepository<ISystemUserRepository>().Context;
            }
        }
    }
}
